#import "RNToolbar.h"
#import "RNToolbarButton.h"
#import "RNLayoutHelper.h"
#import "RNLayoutPopUpButton.h"

CGFloat const RNToolbarButtonPadding = 10.0f;
CGFloat const RNToolbarVerticalPadding = 9.0f;
CGFloat const RNToolbarHeightWithTitles = 65.0f;
CGFloat const RNToolbarHeightWithoutTitles = 40.0f;

NSString* const RNToolbarFlexibleSpaceButtonIdentifier = @"RNToolbarFlexibleSpaceButtonIdentifier";
NSString* const RNToolbarShowsTitlesKey = @"RNToolbarShowsTitlesKey";
NSString* const RNToolbarDelegateKey = @"RNToolbarDelegateKey";
NSString* const RNToolbarShouldHideTitlesKey = @"RNToolbarShouldHideTitlesKey";

#pragma mark -
@interface RNToolbar ()
@property (nonatomic, assign) BOOL visibleButtonsNeedUpdate;
@property (nonatomic, assign) BOOL needsTile;
@property (nonatomic, retain) NSArray *buttons;
@property (nonatomic, retain) NSArray *visibleButtons;
@property (nonatomic, assign) CGFloat sumButtonWidth;
@end

#pragma mark -
@interface RNToolbar (RNToolbarPrivateMethods)
-(void)updateVisibleButtons_;
-(void)initialize_;
-(CGFloat)preferredHeight_;
-(void)sizeToFit;
@end


#pragma mark -
@implementation RNToolbar

@synthesize buttons = buttons_;
@synthesize overflowButton = overflowButton_;
@synthesize showsTitles = showsTitles_;
@synthesize delegate = delegate_;
@synthesize visibleButtonsNeedUpdate = visibleButtonsNeedUpdate_;
@synthesize needsTile = needsTile_;
@synthesize visibleButtons = visibleButtons_;
@synthesize sumButtonWidth = sumButtonWidth_;
@synthesize backgroundGradient = backgroundGradient_;
@synthesize borderColor = borderColor_;

#pragma mark -
#pragma mark Class methods

+ (NSFocusRingType)defaultFocusRingType {
    return NSFocusRingTypeNone;
}


#pragma mark -
#pragma mark Initialization

-(id)initWithFrame:(NSRect)frame {
    if (!(self = [super initWithFrame:frame]))
        return nil;
    [self initialize_];
    return self;
}

-(id)initWithCoder:(NSCoder *)coder {
    if (!(self = [super initWithCoder:coder]))
        return nil;
    [self setDelegate:[coder decodeObjectForKey:RNToolbarDelegateKey]];
    [self initialize_];
    return self;
}

-(void)encodeWithCoder:(NSCoder *)coder {
    [super encodeWithCoder:coder];
    
    [coder encodeConditionalObject:[self delegate] forKey:RNToolbarDelegateKey];
}

-(void)initialize_ {
    [self setShowsTitles:![[NSUserDefaults standardUserDefaults] boolForKey:RNToolbarShouldHideTitlesKey]];
//    [self setPostsFrameChangedNotifications:NO];
    NSRect overflowRect = NSZeroRect;
    NSImage *overflowIndicatorImage = [NSImage imageNamed:@"OverflowIndicator.tiff"];
    overflowRect.size.width = 2 * [overflowIndicatorImage size].width;
    overflowRect.size.height = 2 * [overflowIndicatorImage size].height;
    RNLayoutPopUpButton *overflowButton = [[RNLayoutPopUpButton alloc] initWithFrame:overflowRect pullsDown:YES];
    [[overflowButton cell] setArrowPosition:NSPopUpNoArrow];
    [overflowButton setImagePosition:NSImageOnly];
    [overflowButton setBordered:NO];
    
    NSMenuItem *overflowIndicatorItem = [[NSMenuItem alloc] initWithTitle:@"" action:NULL keyEquivalent:@""];
    [overflowIndicatorItem setImage:overflowIndicatorImage];
    NSMenu *popUpMenu = [overflowButton menu];
    [popUpMenu addItem:overflowIndicatorItem];
    
    [[overflowButton layoutHelper] setHorizontalLayoutType:RNHorizontalRight];
    [[overflowButton layoutHelper] setVerticalLayoutType:RNVerticalCenter];
    [[overflowButton layoutHelper] setRightPadding:RNToolbarButtonPadding];
    [self setOverflowButton:overflowButton];

    [self setBackgroundGradient:[[NSGradient alloc] initWithStartingColor:[NSColor colorWithCalibratedWhite:0.85 alpha:1.0] endingColor:[NSColor colorWithCalibratedWhite:0.95 alpha:1.0]]];
    [self setBorderColor:[NSColor blackColor]];
    
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(validateVisibleItems) name:NSWindowDidUpdateNotification object:[NSApp mainWindow]];
}

-(void)sizeToFit {
    CGFloat height = [self showsTitles] ? RNToolbarHeightWithTitles : RNToolbarHeightWithoutTitles;
    NSRect frame = [self frame];
    frame.size.height = height;
    [self setFrame:frame];
}


#pragma mark -
#pragma mark Drawing

-(void)viewWillDraw {
    [super viewWillDraw];
    if ([self visibleButtonsNeedUpdate]) 
        [self updateVisibleButtons_];
    if ([self needsTile]) {
        [self setNeedsTile:NO];
        [[self layoutHelper] tile];
    }
}

-(void)drawRect:(NSRect)frame {
    [[self backgroundGradient] drawInRect:[self bounds] angle:90];
    [[self borderColor] setStroke];
    NSRect bounds = [self bounds];
    // TODO: CHANGE BORDER COLOR WHEN APP RESIGNS ACTIVE
    [NSBezierPath strokeLineFromPoint:NSMakePoint(NSMinX(bounds), NSMaxY(bounds)) toPoint:NSMakePoint(NSMaxX(bounds), NSMaxY(bounds))];
}

-(void)validateVisibleItems {
    if ([[self visibleButtons] count] == 0)
        return;
    for (RNToolbarButton *button in [self visibleButtons]) {
        if (![NSApp isActive]) {
            [button setEnabled:NO];
            continue;
        }
        id validator = [NSApp targetForAction:[button action] to:[button target] from:button];
//        SEL action = [button action];
//        NSLog(@"%@", NSStringFromSelector(action));
//        if ([button action] == @selector(clearCompletedItems:))
//            NSLog(@"break");
     
        if (validator != nil && ![validator respondsToSelector:[button action]]) 
             [button setEnabled:NO];
        else if ([validator respondsToSelector:@selector(validateToolbarButton:)]) 
            [button setEnabled:[validator validateToolbarButton:button]];
        else if ([validator respondsToSelector:@selector(validateUserInterfaceItem:)])
            [button setEnabled:[validator validateUserInterfaceItem:button]];
        else
             [button setEnabled:YES];
    }
//    [self setVisibleButtonsNeedUpdate:YES];
}


#pragma mark -
#pragma mark Geometry

-(void)setShowsTitles:(BOOL)shouldShowTitles {
    showsTitles_ = shouldShowTitles;
    for (RNToolbarButton *button in [self buttons]) {
        [button setImagePosition:shouldShowTitles ? NSImageAbove : NSImageOnly];
        [button sizeToFit];
    }
    [self sizeToFit];
    [[NSUserDefaults standardUserDefaults] setBool:!shouldShowTitles forKey:RNToolbarShouldHideTitlesKey];
}

-(void)setFrameSize:(NSSize)size {
    [super setFrameSize:size];
    [self setVisibleButtonsNeedUpdate:YES];
}


#pragma mark -
#pragma mark Data
-(void)updateToolbar {
    if (![self delegate])
        return;
    
    // Get rid of old buttons
    [[self buttons] makeObjectsPerformSelector:@selector(removeFromSuperview)];
    
    // Get identifiers and buttons from delegate
    NSArray *identifiers = [[self delegate] buttonIdentifiersForToolbar:self];
    NSMutableArray *newItems = [NSMutableArray arrayWithCapacity:[identifiers count]];
    RNToolbarButton *currentToolbarButton = nil;
    CGFloat newSumButtonWidth = 0;
    
    for (NSString *identifier in identifiers) {
        if ([identifier isEqualToString:RNToolbarFlexibleSpaceButtonIdentifier]) 
            currentToolbarButton = [RNToolbarButton flexibleSpaceButton];
        else {
            currentToolbarButton = [[self delegate] toolbar:self toolbarButtonForIdentifier:identifier];
            [currentToolbarButton setImagePosition:([self showsTitles] ? NSImageAbove : NSImageOnly)];
            [currentToolbarButton sizeToFit];
            newSumButtonWidth += NSWidth([currentToolbarButton frame]) + RNToolbarButtonPadding;
        }
        if (identifier == [identifiers lastObject]) {
            [[currentToolbarButton layoutHelper] setRightPadding:RNToolbarButtonPadding];
            newSumButtonWidth += RNToolbarButtonPadding;
        }
        [[currentToolbarButton layoutHelper] setLeftPadding:RNToolbarButtonPadding];
        [newItems addObject:currentToolbarButton];
    }
    [self setSumButtonWidth:newSumButtonWidth];
    [self setButtons:newItems];
    [self setNeedsTile:YES];
//    [self validateVisibleItems];
    [self setVisibleButtonsNeedUpdate:YES];
}


#pragma mark -
#pragma mark Private

-(void)updateVisibleButtons_ {
    [self setVisibleButtonsNeedUpdate:NO];
    [self setNeedsTile:YES];
    CGFloat availableWidth = NSWidth([self bounds]);
    // If there's plenty of room, set all buttons visible and return
    if (availableWidth >= [self sumButtonWidth]) {
        [self setSubviews:[self buttons]];
        NSArray *nonSpaceButtons = [[self buttons] filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:@"!(identifier like %@)", RNToolbarFlexibleSpaceButtonIdentifier]];
        [self setVisibleButtons:[NSArray arrayWithArray:nonSpaceButtons]];
        [[self overflowButton] removeFromSuperview];
        [self validateVisibleItems];
        return;
    }
    
    // Display the overflow indicator on the right
    if ([[self overflowButton] superview] != self) {
        [self addSubview:[self overflowButton]];
    }
    availableWidth -= NSWidth([[self overflowButton] frame]) + [[[self overflowButton] layoutHelper] leftPadding] + [[[self overflowButton] layoutHelper] rightPadding];
    
    NSInteger buttonIndex = 0;
    NSInteger buttonCount = [[self buttons] count];
    NSMutableArray *newVisibleButtons = [NSMutableArray array];
    
    // Go through buttons left to right, remove spaces, ensure buttons that fit are displayed
    while (buttonIndex < buttonCount) {
        RNToolbarButton *toolbarButton = [[self buttons] objectAtIndex:buttonIndex];
        if ([[toolbarButton identifier] isEqualToString:RNToolbarFlexibleSpaceButtonIdentifier]) {
            [toolbarButton removeFromSuperview];
            buttonIndex++;
            continue;
        }

        CGFloat toolbarButtonWidth = NSWidth([toolbarButton frame]) + [[toolbarButton layoutHelper] leftPadding] + [[toolbarButton layoutHelper] rightPadding];
        if (availableWidth < toolbarButtonWidth) {
            break;
        }
        if ([toolbarButton superview] != self) 
            [self addSubview:toolbarButton];
        [newVisibleButtons addObject:toolbarButton];
        availableWidth -= toolbarButtonWidth;
        buttonIndex++;
    }
    [self setVisibleButtons:(NSArray *)newVisibleButtons];
    
    // Reset popup menu for overflow indicator
    NSMenuItem *overflowIndicatorItem = [[self overflowButton] itemAtIndex:0];
    [[self overflowButton] removeAllItems];
    [[[self overflowButton] menu] addItem:overflowIndicatorItem];
    
    // Remove buttons that don't fit, add them to the overflow indicator's popup menu
    while (buttonIndex < buttonCount) {
        RNToolbarButton *toolbarButton = [[self buttons] objectAtIndex:buttonIndex++];
        [toolbarButton removeFromSuperview];
        if ([[toolbarButton identifier] isEqualToString:RNToolbarFlexibleSpaceButtonIdentifier]) {
            if ([[self overflowButton] numberOfItems] == 0)
                continue;
            [[[self overflowButton] menu] addItem:[NSMenuItem separatorItem]];
        } 
        else {
            [[self overflowButton] addItemWithTitle:[toolbarButton title]];
            NSMenuItem *lastItem = [[self overflowButton] lastItem];
            NSImage *buttonImage = [[toolbarButton image] copy];
            CGFloat menuPointSize = [[NSFont menuFontOfSize:0] pointSize];
            [buttonImage setSize:NSMakeSize(menuPointSize, menuPointSize)];
            [lastItem setImage:buttonImage];
            [lastItem setAction:[toolbarButton action]];
            [lastItem setTarget:[toolbarButton target]];
        }
    }
    [self validateVisibleItems];
}

@end

